import { computed, shallowRef } from 'vue'
import localforage from 'localforage'
import { useManualRefHistory } from '@vueuse/core'
import { useViewportStore } from '@renderer/stores/viewport'
import { storeToRefs } from 'pinia'
import { Box3, Group, Vector3 } from 'three'
import { ObjectLoader } from './ObjectLoader'
import emiter from './mitt'
import { ElMessageBox } from 'element-plus'

localforage.config({
  driver: localforage.INDEXEDDB,
  name: 'wlz-3d-editor'
})

const historyVO = shallowRef({
  camera: {},
  publicGroup: {} as Group
})

const historyItem = shallowRef({
  name: '',
  objects: {} as Group,
  type: '',
  time: 0
})

const loader = new ObjectLoader()

const viewportStore = useViewportStore()
const { scene, publicGroup, camera } = storeToRefs(viewportStore)

const { history, redoStack, undoStack, last, commit, undo, redo, clear } = useManualRefHistory(
  historyItem,
  {
    dump: (value) => {
      return JSON.parse(JSON.stringify(value))
    },
    parse: (json: any) => {
      praseObject(json)
      return json
    }
  }
)

function praseObject(snapshot: any) {
  if (publicGroup.value) {
    const group = loader.parse(snapshot.objects)
    group.traverse((node) => {
      // 修改巷道中心点
      if (node.geometry?.type === 'TunnelGeometry') {
        node.geometry.computeBoundingBox()
        const box3 = new Box3()
        box3.expandByObject(node)
        const center = new Vector3(0)
        box3.getCenter(center)
        node.position.copy(center)
        node.geometry.center()
      }
      // if (node.uuid === activeVO.value?.uuid) {
      //   activeObjectStore.setActiveVO(node)
      // }
    })
    while (publicGroup.value.children.length > 0) {
      const child = publicGroup.value.children[0]
      publicGroup.value.remove(child)
    }
    publicGroup.value.add(...group.children)
    emiter.emit('viewChange')
  }
}

const undoStackList = computed(() => {
  const list = history.value.slice()
  list.pop() // 去掉初始化时产生的历史纪录
  return list.reverse()
})

export const useHistory = () => {
  function commitHistory(name: string, type: string) {
    if (publicGroup.value && camera.value) {
      historyVO.value.publicGroup = publicGroup.value
      historyVO.value.camera = camera.value
    }

    historyItem.value = {
      type: type,
      name: name,
      objects: historyVO.value.publicGroup,
      time: Date.now()
    }
    commit()
    saveLocalHistory()
  }

  function getLocalHistory() {
    localforage.getItem('app-history').then((appHistory: any) => {
      if (appHistory && appHistory.scene) {
        redoStack.value = appHistory.history.redoStack
        undoStack.value = appHistory.history.undoStack
        last.value = appHistory.history.last
        // 将场景恢复成当前记录
        praseObject(last.value.snapshot)
        // 将视角也还原
        if (scene.value && appHistory.camera.object) {
          for (let i = scene.value.children.length - 1; i >= 0; i--) {
            const item = scene.value.children[i]
            if (item.name === 'tresPerspectiveCamera') {
              const camera = loader.parse(appHistory.camera)
              item.position.copy(camera.position)
              item.rotation.copy(camera.rotation)
            }
          }
        }
      }
    })
  }

  function saveLocalHistory() {
    const params = {
      camera: historyVO.value.camera,
      publicGroup: historyVO.value.publicGroup,
      history: {
        redoStack: redoStack.value,
        undoStack: undoStack.value,
        last: last.value
      }
    }

    localforage.setItem('app-history', JSON.parse(JSON.stringify(params)))
  }

  function handleUndo(index: number) {
    let undoLength = undoStackList.value.length - index - 1 // 撤销几次
    while (undoLength > 0) {
      undo()
      undoLength--
    }
    saveLocalHistory()
  }

  function handleRedo(index: number) {
    let redoLength = index + 1 // 重做几次
    while (redoLength > 0) {
      redo()
      redoLength--
    }
    saveLocalHistory()
  }

  function clearLocalHistory() {
    ElMessageBox.confirm('撤销/重做历史记录将被清除。您确定吗？', 'Warning', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning'
    }).then(() => {
      clear()
      localforage.removeItem('app-history')
    })
  }

  return {
    redoStack,
    undoStackList,
    handleRedo,
    handleUndo,
    commitHistory,
    clearLocalHistory,
    getLocalHistory
  }
}
